webrtc/modules/audio_device/android/audio_record_jni.cc
这个文件,是音频采集jni类文件。
Android Audio Record 和 JNI 通信接口包括:
1 | // java 调用 c++ 接口 |
1 | // c++ 回调 java 接口 |
nativeCacheDirectBufferAddress 和 nativeDataIsRecorded 只是为了高效的将 AudioRecord 采集到的音频数据传递给 native。
WebRtcVoiceEngine
WebRtcVoiceEngine 初始化
1 | WebRtcVoiceEngine::Init(){ |
可知,WebRtcVoiceEngine 里面的 adm_ 就是 AudioDeviceModule ,代码在 /modules/audio_device/audio_device_impl.cc
在 webrtcvoiceengine.h1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27// WebRtcVoiceEngine
//public
void Init();
AudioState GetAudioState();
VoiceMediaChannel* CreateChannel(Call call, MediaConfig config, AudioOptions options);
AudioCodec send_codecs();
AudioCodec recv_codecs();
RtpCapabilities GetCapabilities();
void RegisterChannel(WebRtcVoiceMediaChannel* channel);
void UnregisterChannel(WebRtcVoiceMediaChannel* channel);
bool StartAecDump();
void StopAecDump();
//private
AudioDeviceModule adm_;
AudioEncoderFactory encoder_factory_;
AudioDecoderFactory decoder_factory_;
AudioMixer audio_mixer_;
AudioProcessing apm_;
AudioState audio_state_;
AudioCodec send_codecs_;
AudioCodec recv_codecs_;
WebRtcVoiceMediaChannel channels_;
audio_device
//webrtc/modules/audio_device/
audio_device_impl.cc
1 | AudioDeviceModule::Create(){ |
1 | AudioDeviceModuleImpl::CreatePlatformSpecificObjects(){ |
我们以 Android 为例;使用 AudioDeviceTemplate 封装 音频输入(采集)、输出类型(渲染);
目前使用 AudioRecordJni 和 AudioTrackJni。
如果直接使用 NDK 的openSLES 开发的化,使用的是 OpenSLESRecorder 和 OpenSLESPlayer。
audio_manager.h1
2
3
4
5
6
7
8
9
10// JavaAudioManager
bool Init()
void Close()
bool IsCommunicationModeEnabled()
bool IsDeviceBlacklistedForOpenSLESUsage()
// private
JNICALL CacheAudioParameters()
void OnCacheAudioParameters()
audio_record_jni.h1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29//JavaAudioRecord
int InitRecording(int sample_reate, size_t channels);
bool StartRecording();
bool StopRecording();
bool EnableBuiltInAEC(bool enable);
bool EnableBuiltInNS(bool enable);
// public
int32_t Init();
int32_t Terminate();
int32_t InitRecording();
bool RecordingIsInitialized();
int32_t StartRecording();
int32_t StopRecording();
bool Recording();
void AttachAudioBuffer();
int32_t EnableBuiltInAEC(bool enable);
int32_t EnableBuiltInAGC(bool enable);
int32_t EnableBuiltInNS(bool enable);
// private
JNICALL CacheDirectBufferAddress()
void OnCacheDirectBufferAddress(jobject byte_buffer)
JNICALL DataIsRecorded();
void OnDataIsRecorded(int length);
audio_track_jni.h
1 | // JavaAudioTrack |
AudioRecordJni
音频采集初始化
AudioRecordJni 初始化时,在构造方法中初始化 JavaAudioRecord。1
2
3j_audio-record_.reset(
new JavaAudioRecord()
)
然后在 webrtcvoiceengine 中 AddSendStream 后,SetSend() 配置媒体通道发送。
1 | //media/engine/webrtcvoiceengine.cc |
这里面会初始化 AudioRecord。
InitRecording() 方法实现,在 Android 中实在 audio_record_jni.cc 的 JavaAudioRecord::InitRecording() ,最终通过 JNI 回调 Java 层的 InitRecording() 方法。
音频采集
初始化完成后,就要开始采集音频数据。
/audio/audio_send_stream.cc
音频发送流里面 AudioSendStream::Start() 方法启动音频流发送;
1 | AudioSendSstream::Start(){ |
调用 /audio/audio_state.cc 的 AudioState::AddSendingStream() 方法;
1 | AudioState::AddSendingStream(){ |
音频开关
另外,PeerConnection 提供了 音频采集开关。
1 | //org.webrtc.PeerConnection.java |
对应的JNI方法1
2
3
4//JNI/pc/peerconnection.cc
void JNI_PeerConnection_SetAudioRecording(){
ExtractNativePC(jni,j_pc)->SetAudioRecording(recording);
}
其实JNI方法也是调用 webrtc 的 peerconnection
1 | //webrtc/pc/peerconnection.cc |
由上代码可知, 通过 WebRtcVoiceEngine 的 GetAudioState() 方法获取 audio_state。
然后通过 audio_state 设置音频采集开关。
在 AudioState::SetRecording() 方法调用具体设备模块开始或停止音频采集。
1 | //webrtc/audio/audio_state.cc |
音频采集具体实现
这里我们只以Android为例。
如果使用 opensles ndk 采集音频,采集的具体实现在 opensles_recorder.cc 文件的 StartRecording() 方法。
1 | // modules/audio_device/android/opensles_recorder.cc |
这种方法的具体实现我们暂时不深入。
我们讨论 java 实现方案。
java 实现的jni类,audio_record_jni.cc1
2
3
4
5
6//modules/audio_device/android/audio_record_jni.cc
AudioRecordJni::StartRecording(){
...
j_audio_record_->StartRecording()
...
}
j_audio_record_->StartRecording() 调用的就是 AudioRecordJni::JavaAudioRecord::StartRecording() 方法。
1 | AudioRecordJni::JavaAudioRecord::StartRecording(){ |
CallBooleanMethod 就是jni回调java 实现的封装,最终实现回调 WebRtcAudioRecord.java 中的 StartRecording() 方法。
1 | //org.webrtc.voiceengine.WebRtcAudioRecord.java |
音频采集线程
音频采集线 AudioRecordThread;我们只跟踪 run() 方法。
1 | @Override |